/*
 * FreeSec: libcrypt for NetBSD
 *
 * contrib/pgcrypto/crypt-des.c
 *
 * Copyright (c) 1994 David Burren
 * All rights reserved.
 *
 * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet
 *	该文件现在应*仅*导出 crypt()，以便使 libcrypt 的
 *	二进制文件能够从美国出口
 *
 * Adapted for FreeBSD-4.0 by Mark R V Murray
 *	该文件现在应*仅*导出 px_crypt_des()，以便使
 *	一个可以选择性包含在 libcrypt 中的模块。
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *	  notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *	  notice, this list of conditions and the following disclaimer in the
 *	  documentation and/or other materials provided with the distribution.
 * 3. 作者的姓名或其他贡献者的姓名不得用于支持或宣传
 *	  从本软件派生的产品，除非事先获得具体的书面许可。
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: src/secure/lib/libcrypt/crypt-des.c,v 1.12 1999/09/20 12:39:20 markm Exp $
 *
 * 这是 David Burren <davidb@werj.com.au> 对 DES 和 crypt(3) 接口
 * 的原始实现。
 *
 * 关于底层算法（及相关算法）的优秀参考书籍是：
 *
 *	B. Schneier, Applied Cryptography: protocols, algorithms,
 *	and source code in C, John Wiley & Sons, 1994.
 *
 * 请注意在该书对 DES 的描述中，初始、pbox 和最终置换的查找是
 * 反向的（这一点已引起作者的注意）。该书的勘误表已由作者在
 * sci.crypt 新闻组中发布，并可以通过 FTP 获取。
 *
 * 架构假设：
 *	假设通过引用传递的 8 字节数组可以被视为 uint32 的数组
 *（即，CPU 对对齐没有严格要求）。
 */

#include "postgres.h"
#include "miscadmin.h"
#include "port/pg_bswap.h"

#include "px-crypt.h"

#define _PASSWORD_EFMT1 '_'

static const char _crypt_a64[] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

static uint8 IP[64] = {
	58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
	62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
	57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
	61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
};

static uint8 inv_key_perm[64];
static uint8 u_key_perm[56];
static uint8 key_perm[56] = {
	57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
	10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
	63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
	14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
};

static uint8 key_shifts[16] = {
	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};

static uint8 inv_comp_perm[56];
static uint8 comp_perm[48] = {
	14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
	23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
	41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
	44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
};

/*
 *	没有使用 E 盒，因为它被一些 AND、移位和 OR 替代。
 */

static uint8 u_sbox[8][64];
static uint8 sbox[8][64] = {
	{
		14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
		0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
		4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
		15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
	},
	{
		15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
		3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
		0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
		13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
	},
	{
		10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
		13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
		13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
		1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
	},
	{
		7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
		13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
		10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
		3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
	},
	{
		2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
		14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
		4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
		11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
	},
	{
		12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
		10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
		9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
		4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
	},
	{
		4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
		13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
		1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
		6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
	},
	{
		13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
		1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
		7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
		2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
	}
};

static uint8 un_pbox[32];
static uint8 pbox[32] = {
	16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
	2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
};

static uint32 _crypt_bits32[32] =
{
	0x80000000, 0x40000000, 0x20000000, 0x10000000,
	0x08000000, 0x04000000, 0x02000000, 0x01000000,
	0x00800000, 0x00400000, 0x00200000, 0x00100000,
	0x00080000, 0x00040000, 0x00020000, 0x00010000,
	0x00008000, 0x00004000, 0x00002000, 0x00001000,
	0x00000800, 0x00000400, 0x00000200, 0x00000100,
	0x00000080, 0x00000040, 0x00000020, 0x00000010,
	0x00000008, 0x00000004, 0x00000002, 0x00000001
};

static uint8 _crypt_bits8[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};

static uint32 saltbits;
static long old_salt;
static uint32 *bits28,
		   *bits24;
static uint8 init_perm[64],
			final_perm[64];
static uint32 en_keysl[16],
			en_keysr[16];
static uint32 de_keysl[16],
			de_keysr[16];
static int	des_initialised = 0;
static uint8 m_sbox[4][4096];
static uint32 psbox[4][256];
static uint32 ip_maskl[8][256],
			ip_maskr[8][256];
static uint32 fp_maskl[8][256],
			fp_maskr[8][256];
static uint32 key_perm_maskl[8][128],
			key_perm_maskr[8][128];
static uint32 comp_maskl[8][128],
			comp_maskr[8][128];
static uint32 old_rawkey0,
			old_rawkey1;

static inline int fc_ascii_to_bin(char fc_ch)
{
	if (fc_ch > 'z')
		return 0;
	if (fc_ch >= 'a')
		return (fc_ch - 'a' + 38);
	if (fc_ch > 'Z')
		return 0;
	if (fc_ch >= 'A')
		return (fc_ch - 'A' + 12);
	if (fc_ch > '9')
		return 0;
	if (fc_ch >= '.')
		return (fc_ch - '.');
	return 0;
}

static void fc_des_init(void)
{
	int			fc_i,
				fc_j,
				fc_b,
				fc_k,
				fc_inbit,
				fc_obit;
	uint32	   *fc_p,
			   *fc_il,
			   *fc_ir,
			   *fc_fl,
			   *fc_fr;

	old_rawkey0 = old_rawkey1 = 0L;
	saltbits = 0L;
	old_salt = 0L;
	bits24 = (bits28 = _crypt_bits32 + 4) + 4;

	/*
	 * 反转 S-盒，重新排列输入位。
	 */
	for (fc_i = 0; fc_i < 8; fc_i++)
		for (fc_j = 0; fc_j < 64; fc_j++)
		{
			fc_b = (fc_j & 0x20) | ((fc_j & 1) << 4) | ((fc_j >> 1) & 0xf);
			u_sbox[fc_i][fc_j] = sbox[fc_i][fc_b];
		}

	/*
	 * 将反转的 S-盒转换为 4 个 8 位数组。每个数组处理
	 * 12 位的 S-盒输入。
	 */
	for (fc_b = 0; fc_b < 4; fc_b++)
		for (fc_i = 0; fc_i < 64; fc_i++)
			for (fc_j = 0; fc_j < 64; fc_j++)
				m_sbox[fc_b][(fc_i << 6) | fc_j] =
					(u_sbox[(fc_b << 1)][fc_i] << 4) |
					u_sbox[(fc_b << 1) + 1][fc_j];

	/*
	 * 将初始和最终置换设置为一个有用的形式，并
	 * 初始化反转的密钥置换。
	 */
	for (fc_i = 0; fc_i < 64; fc_i++)
	{
		init_perm[final_perm[fc_i] = IP[fc_i] - 1] = fc_i;
		inv_key_perm[fc_i] = 255;
	}

	/*
	 * 反转密钥置换并初始化反转的密钥压缩
	 * 置换。
	 */
	for (fc_i = 0; fc_i < 56; fc_i++)
	{
		u_key_perm[fc_i] = key_perm[fc_i] - 1;
		inv_key_perm[key_perm[fc_i] - 1] = fc_i;
		inv_comp_perm[fc_i] = 255;
	}

	/*
	 * 反转密钥压缩置换。
	 */
	for (fc_i = 0; fc_i < 48; fc_i++)
		inv_comp_perm[comp_perm[fc_i] - 1] = fc_i;

	/*
	 * 为初始和最终置换以及密钥初始和压缩置换设置 OR 掩码数组。
	 */
	for (fc_k = 0; fc_k < 8; fc_k++)
	{
		for (fc_i = 0; fc_i < 256; fc_i++)
		{
			*(fc_il = &ip_maskl[fc_k][fc_i]) = 0L;
			*(fc_ir = &ip_maskr[fc_k][fc_i]) = 0L;
			*(fc_fl = &fp_maskl[fc_k][fc_i]) = 0L;
			*(fc_fr = &fp_maskr[fc_k][fc_i]) = 0L;
			for (fc_j = 0; fc_j < 8; fc_j++)
			{
				fc_inbit = 8 * fc_k + fc_j;
				if (fc_i & _crypt_bits8[fc_j])
				{
					if ((fc_obit = init_perm[fc_inbit]) < 32)
						*fc_il |= _crypt_bits32[fc_obit];
					else
						*fc_ir |= _crypt_bits32[fc_obit - 32];
					if ((fc_obit = final_perm[fc_inbit]) < 32)
						*fc_fl |= _crypt_bits32[fc_obit];
					else
						*fc_fr |= _crypt_bits32[fc_obit - 32];
				}
			}
		}
		for (fc_i = 0; fc_i < 128; fc_i++)
		{
			*(fc_il = &key_perm_maskl[fc_k][fc_i]) = 0L;
			*(fc_ir = &key_perm_maskr[fc_k][fc_i]) = 0L;
			for (fc_j = 0; fc_j < 7; fc_j++)
			{
				fc_inbit = 8 * fc_k + fc_j;
				if (fc_i & _crypt_bits8[fc_j + 1])
				{
					if ((fc_obit = inv_key_perm[fc_inbit]) == 255)
						continue;
					if (fc_obit < 28)
						*fc_il |= bits28[fc_obit];
					else
						*fc_ir |= bits28[fc_obit - 28];
				}
			}
			*(fc_il = &comp_maskl[fc_k][fc_i]) = 0L;
			*(fc_ir = &comp_maskr[fc_k][fc_i]) = 0L;
			for (fc_j = 0; fc_j < 7; fc_j++)
			{
				fc_inbit = 7 * fc_k + fc_j;
				if (fc_i & _crypt_bits8[fc_j + 1])
				{
					if ((fc_obit = inv_comp_perm[fc_inbit]) == 255)
						continue;
					if (fc_obit < 24)
						*fc_il |= bits24[fc_obit];
					else
						*fc_ir |= bits24[fc_obit - 24];
				}
			}
		}
	}

	/*
	 * 反转 P-盒置换，并转换为 OR 掩码以处理
	 * 上面设置的 S-盒数组的输出。
	 */
	for (fc_i = 0; fc_i < 32; fc_i++)
		un_pbox[pbox[fc_i] - 1] = fc_i;

	for (fc_b = 0; fc_b < 4; fc_b++)
		for (fc_i = 0; fc_i < 256; fc_i++)
		{
			*(fc_p = &psbox[fc_b][fc_i]) = 0L;
			for (fc_j = 0; fc_j < 8; fc_j++)
			{
				if (fc_i & _crypt_bits8[fc_j])
					*fc_p |= _crypt_bits32[un_pbox[8 * fc_b + fc_j]];
			}
		}

	des_initialised = 1;
}

static void fc_setup_salt(long fc_salt)
{
	uint32		fc_obit,
				fc_saltbit;
	int			fc_i;

	if (fc_salt == old_salt)
		return;
	old_salt = fc_salt;

	saltbits = 0L;
	fc_saltbit = 1;
	fc_obit = 0x800000;
	for (fc_i = 0; fc_i < 24; fc_i++)
	{
		if (fc_salt & fc_saltbit)
			saltbits |= fc_obit;
		fc_saltbit <<= 1;
		fc_obit >>= 1;
	}
}

static int fc_des_setkey(const char *fc_key)
{
	uint32		fc_k0,
				fc_k1,
				fc_rawkey0,
				fc_rawkey1;
	int			fc_shifts,
				fc_round;

	if (!des_initialised)
		fc_des_init();

	fc_rawkey0 = pg_ntoh32(*(const uint32 *) fc_key);
	fc_rawkey1 = pg_ntoh32(*(const uint32 *) (fc_key + 4));

	if ((fc_rawkey0 | fc_rawkey1)
		&& fc_rawkey0 == old_rawkey0
		&& fc_rawkey1 == old_rawkey1)
	{
		/*
		 * 已经为这个密钥设置好。这个优化在零密钥
		 * （本身是弱密钥并且有坏奇偶性）上失败，以简化
		 * 初始条件。
		 */
		return 0;
	}
	old_rawkey0 = fc_rawkey0;
	old_rawkey1 = fc_rawkey1;

	/*
	 * 进行密钥置换并分成两个 28 位子密钥。
	 */
	fc_k0 = key_perm_maskl[0][fc_rawkey0 >> 25]
		| key_perm_maskl[1][(fc_rawkey0 >> 17) & 0x7f]
		| key_perm_maskl[2][(fc_rawkey0 >> 9) & 0x7f]
		| key_perm_maskl[3][(fc_rawkey0 >> 1) & 0x7f]
		| key_perm_maskl[4][fc_rawkey1 >> 25]
		| key_perm_maskl[5][(fc_rawkey1 >> 17) & 0x7f]
		| key_perm_maskl[6][(fc_rawkey1 >> 9) & 0x7f]
		| key_perm_maskl[7][(fc_rawkey1 >> 1) & 0x7f];
	fc_k1 = key_perm_maskr[0][fc_rawkey0 >> 25]
		| key_perm_maskr[1][(fc_rawkey0 >> 17) & 0x7f]
		| key_perm_maskr[2][(fc_rawkey0 >> 9) & 0x7f]
		| key_perm_maskr[3][(fc_rawkey0 >> 1) & 0x7f]
		| key_perm_maskr[4][fc_rawkey1 >> 25]
		| key_perm_maskr[5][(fc_rawkey1 >> 17) & 0x7f]
		| key_perm_maskr[6][(fc_rawkey1 >> 9) & 0x7f]
		| key_perm_maskr[7][(fc_rawkey1 >> 1) & 0x7f];

	/*
	 * 旋转子密钥并进行压缩置换。
	 */
	fc_shifts = 0;
	for (fc_round = 0; fc_round < 16; fc_round++)
	{
		uint32		fc_t0,
					fc_t1;

		fc_shifts += key_shifts[fc_round];

		fc_t0 = (fc_k0 << fc_shifts) | (fc_k0 >> (28 - fc_shifts));
		fc_t1 = (fc_k1 << fc_shifts) | (fc_k1 >> (28 - fc_shifts));

		de_keysl[15 - fc_round] =
			en_keysl[fc_round] = comp_maskl[0][(fc_t0 >> 21) & 0x7f]
			| comp_maskl[1][(fc_t0 >> 14) & 0x7f]
			| comp_maskl[2][(fc_t0 >> 7) & 0x7f]
			| comp_maskl[3][fc_t0 & 0x7f]
			| comp_maskl[4][(fc_t1 >> 21) & 0x7f]
			| comp_maskl[5][(fc_t1 >> 14) & 0x7f]
			| comp_maskl[6][(fc_t1 >> 7) & 0x7f]
			| comp_maskl[7][fc_t1 & 0x7f];

		de_keysr[15 - fc_round] =
			en_keysr[fc_round] = comp_maskr[0][(fc_t0 >> 21) & 0x7f]
			| comp_maskr[1][(fc_t0 >> 14) & 0x7f]
			| comp_maskr[2][(fc_t0 >> 7) & 0x7f]
			| comp_maskr[3][fc_t0 & 0x7f]
			| comp_maskr[4][(fc_t1 >> 21) & 0x7f]
			| comp_maskr[5][(fc_t1 >> 14) & 0x7f]
			| comp_maskr[6][(fc_t1 >> 7) & 0x7f]
			| comp_maskr[7][fc_t1 & 0x7f];
	}
	return 0;
}

static int fc_do_des(uint32 fc_l_in, uint32 fc_r_in, uint32 *fc_l_out, uint32 *fc_r_out, int fc_count)
{
	/*
	 * l_in, r_in, l_out 和 r_out 为伪“高位优先”格式。
	 */
	uint32		fc_l,
				fc_r,
			   *fc_kl,
			   *fc_kr,
			   *fc_kl1,
			   *fc_kr1;
	uint32		fc_f,
				fc_r48l,
				fc_r48r;
	int			fc_round;

	if (fc_count == 0)
		return 1;
	else if (fc_count > 0)
	{
		/*
		 * 加密
		 */
		fc_kl1 = en_keysl;
		fc_kr1 = en_keysr;
	}
	else
	{
		/*
		 * 解密
		 */
		fc_count = -fc_count;
		fc_kl1 = de_keysl;
		fc_kr1 = de_keysr;
	}

	/*
	 * 进行初始置换 (IP)。
	 */
	fc_l = ip_maskl[0][fc_l_in >> 24]
		| ip_maskl[1][(fc_l_in >> 16) & 0xff]
		| ip_maskl[2][(fc_l_in >> 8) & 0xff]
		| ip_maskl[3][fc_l_in & 0xff]
		| ip_maskl[4][fc_r_in >> 24]
		| ip_maskl[5][(fc_r_in >> 16) & 0xff]
		| ip_maskl[6][(fc_r_in >> 8) & 0xff]
		| ip_maskl[7][fc_r_in & 0xff];
	fc_r = ip_maskr[0][fc_l_in >> 24]
		| ip_maskr[1][(fc_l_in >> 16) & 0xff]
		| ip_maskr[2][(fc_l_in >> 8) & 0xff]
		| ip_maskr[3][fc_l_in & 0xff]
		| ip_maskr[4][fc_r_in >> 24]
		| ip_maskr[5][(fc_r_in >> 16) & 0xff]
		| ip_maskr[6][(fc_r_in >> 8) & 0xff]
		| ip_maskr[7][fc_r_in & 0xff];

	while (fc_count--)
	{
		CHECK_FOR_INTERRUPTS();

		/*
		 * 进行每一轮。
		 */
		fc_kl = fc_kl1;
		fc_kr = fc_kr1;
		fc_round = 16;
		while (fc_round--)
		{
			/*
			 * 将 R 扩展为 48 位（模拟 E-盒）。
			 */
			fc_r48l = ((fc_r & 0x00000001) << 23)
				| ((fc_r & 0xf8000000) >> 9)
				| ((fc_r & 0x1f800000) >> 11)
				| ((fc_r & 0x01f80000) >> 13)
				| ((fc_r & 0x001f8000) >> 15);

			fc_r48r = ((fc_r & 0x0001f800) << 7)
				| ((fc_r & 0x00001f80) << 5)
				| ((fc_r & 0x000001f8) << 3)
				| ((fc_r & 0x0000001f) << 1)
				| ((fc_r & 0x80000000) >> 31);

			/*
			 * 对 crypt() 和相关函数进行盐化，并与置换
			 * 密钥进行异或。
			 */
			fc_f = (fc_r48l ^ fc_r48r) & saltbits;
			fc_r48l ^= fc_f ^ *fc_kl++;
			fc_r48r ^= fc_f ^ *fc_kr++;

			/*
			 * 进行 S-盒查找（将其缩回 32 位）并同时进行
			 * P-盒置换。
			 */
			fc_f = psbox[0][m_sbox[0][fc_r48l >> 12]]
				| psbox[1][m_sbox[1][fc_r48l & 0xfff]]
				| psbox[2][m_sbox[2][fc_r48r >> 12]]
				| psbox[3][m_sbox[3][fc_r48r & 0xfff]];

			/*
			 * 现在我们已进行置换，完成 f()。
			 */
			fc_f ^= fc_l;
			fc_l = fc_r;
			fc_r = fc_f;
		}
		fc_r = fc_l;
		fc_l = fc_f;
	}

	/*
	 * 进行最终置换（IP 的逆）。
	 */
	*fc_l_out = fp_maskl[0][fc_l >> 24]
		| fp_maskl[1][(fc_l >> 16) & 0xff]
		| fp_maskl[2][(fc_l >> 8) & 0xff]
		| fp_maskl[3][fc_l & 0xff]
		| fp_maskl[4][fc_r >> 24]
		| fp_maskl[5][(fc_r >> 16) & 0xff]
		| fp_maskl[6][(fc_r >> 8) & 0xff]
		| fp_maskl[7][fc_r & 0xff];
	*fc_r_out = fp_maskr[0][fc_l >> 24]
		| fp_maskr[1][(fc_l >> 16) & 0xff]
		| fp_maskr[2][(fc_l >> 8) & 0xff]
		| fp_maskr[3][fc_l & 0xff]
		| fp_maskr[4][fc_r >> 24]
		| fp_maskr[5][(fc_r >> 16) & 0xff]
		| fp_maskr[6][(fc_r >> 8) & 0xff]
		| fp_maskr[7][fc_r & 0xff];
	return 0;
}

static int fc_des_cipher(const char *fc_in, char *fc_out, long fc_salt, int fc_count)
{
	uint32		fc_buffer[2];
	uint32		fc_l_out,
				fc_r_out,
				fc_rawl,
				fc_rawr;
	int			fc_retval;

	if (!des_initialised)
		fc_des_init();

	fc_setup_salt(fc_salt);

	/* 复制数据以避免假设输入是字对齐的 */
	memcpy(fc_buffer, fc_in, sizeof(fc_buffer));

	fc_rawl = pg_ntoh32(fc_buffer[0]);
	fc_rawr = pg_ntoh32(fc_buffer[1]);

	fc_retval = fc_do_des(fc_rawl, fc_rawr, &fc_l_out, &fc_r_out, fc_count);
	if (fc_retval)
		return fc_retval;

	fc_buffer[0] = pg_hton32(fc_l_out);
	fc_buffer[1] = pg_hton32(fc_r_out);

	/* 复制数据以避免假设输出是字对齐的 */
	memcpy(fc_out, fc_buffer, sizeof(fc_buffer));
#ifdef FDD //cppcheck
	//cppcheck:CWE-398 相同条件和返回表达式'retval'，返回值总是0
	return 0;
#else
	return fc_retval;
#endif
}

char * px_crypt_des(const char *fc_key, const char *fc_setting)
{
	int			fc_i;
	uint32		fc_count,
				fc_salt,
				fc_l,
				fc_r0,
				fc_r1,
				fc_keybuf[2];
	char	   *fc_p;
	uint8	   *fc_q;
	static char fc_output[21];

	if (!des_initialised)
		fc_des_init();


	/*
	 * 复制密钥，将每个字符向上移动一个位并填充零。
	 */
	fc_q = (uint8 *) fc_keybuf;
	while (fc_q - (uint8 *) fc_keybuf - 8)
	{
		*fc_q++ = *fc_key << 1;
		if (*fc_key != '\0')
			fc_key++;
	}
	if (fc_des_setkey((char *) fc_keybuf))
		return NULL;

#ifndef DISABLE_XDES
	if (*fc_setting == _PASSWORD_EFMT1)
	{
		/*
		 * “新”风格：设置必须是一个 9 字符（下划线，然后是 4
		 * 字节的计数，然后是 4 字节的盐）字符串。详见 CRYPT(3) 中的
		 * “扩展加密”标题以获取更多细节。
		 *
		 * 输入密钥的无限字符被使用。这被称为
		 * “扩展加密”DES方法。
		 *
		 */
		if (strlen(fc_setting) < 9)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("invalid salt")));

		for (fc_i = 1, fc_count = 0L; fc_i < 5; fc_i++)
			fc_count |= fc_ascii_to_bin(fc_setting[fc_i]) << (fc_i - 1) * 6;

		for (fc_i = 5, fc_salt = 0L; fc_i < 9; fc_i++)
			fc_salt |= fc_ascii_to_bin(fc_setting[fc_i]) << (fc_i - 5) * 6;

		while (*fc_key)
		{
			/*
			 * 用密钥自身加密。
			 */
			if (fc_des_cipher((char *) fc_keybuf, (char *) fc_keybuf, 0L, 1))
				return NULL;

			/*
			 * 并与密钥的下 8 个字符进行异或。
			 */
			fc_q = (uint8 *) fc_keybuf;
			while (fc_q - (uint8 *) fc_keybuf - 8 && *fc_key)
				*fc_q++ ^= *fc_key++ << 1;

			if (fc_des_setkey((char *) fc_keybuf))
				return NULL;
		}
		strlcpy(fc_output, fc_setting, 10);

		/*
		 * 再次检查我们是否没有收到短设置。如果是，上面的代码
		 * 可能会为计数和盐创建奇怪的值，但我们并不太在意。只需确保输出字符串
		 * 中没有额外的 NUL。
		 */
		fc_p = fc_output + strlen(fc_output);
	}
	else
#endif							/* !DISABLE_XDES */
	{
		/*
		 * “旧”风格：设置 - 2 字节的盐密钥 - 仅使用输入密钥的前 8
		 * 个字符。
		 */
		fc_count = 25;

		if (strlen(fc_setting) < 2)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("invalid salt")));

		fc_salt = (fc_ascii_to_bin(fc_setting[1]) << 6)
			| fc_ascii_to_bin(fc_setting[0]);

		fc_output[0] = fc_setting[0];

		/*
		 * 如果提取盐值的加密密码仅长1个字符，盐值将会被破坏。我们需要确保输出字符串中没有额外的NUL！
		 */
		fc_output[1] = fc_setting[1] ? fc_setting[1] : fc_output[0];

		fc_p = fc_output + 2;
	}
	fc_setup_salt(fc_salt);

	/*
	 * 开始执行。
	 */
	if (fc_do_des(0L, 0L, &fc_r0, &fc_r1, fc_count))
		return NULL;

	/*
	 * 现在对结果进行编码...
	 */
	fc_l = (fc_r0 >> 8);
	*fc_p++ = _crypt_a64[(fc_l >> 18) & 0x3f];
	*fc_p++ = _crypt_a64[(fc_l >> 12) & 0x3f];
	*fc_p++ = _crypt_a64[(fc_l >> 6) & 0x3f];
	*fc_p++ = _crypt_a64[fc_l & 0x3f];

	fc_l = (fc_r0 << 16) | ((fc_r1 >> 16) & 0xffff);
	*fc_p++ = _crypt_a64[(fc_l >> 18) & 0x3f];
	*fc_p++ = _crypt_a64[(fc_l >> 12) & 0x3f];
	*fc_p++ = _crypt_a64[(fc_l >> 6) & 0x3f];
	*fc_p++ = _crypt_a64[fc_l & 0x3f];

	fc_l = fc_r1 << 2;
	*fc_p++ = _crypt_a64[(fc_l >> 12) & 0x3f];
	*fc_p++ = _crypt_a64[(fc_l >> 6) & 0x3f];
	*fc_p++ = _crypt_a64[fc_l & 0x3f];
	*fc_p = 0;

	return fc_output;
}
